package org.sws.domain.strategy.service.armory.algorithm.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.sws.domain.strategy.model.entity.StrategyAwardEntity;
import org.sws.domain.strategy.model.valobj.StrategyAwardRateRangeVO;
import org.sws.domain.strategy.repository.IStrategyRepository;
import org.sws.domain.strategy.service.armory.algorithm.IAlgorithm;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.security.SecureRandom;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author sws
 * @Date 2025/4/23 09:13
 * @description:
 */
@Slf4j
@Service("oLogNAlgorithm")
public class OLogNAlgorithm implements IAlgorithm {

    @Resource
    private IStrategyRepository strategyRepository;

    private final Random secureRandom = new SecureRandom();
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    /*
     * 如概率值为；3、4、2、9，存储为 [1~3]、[4~7]、[8~9]、[10~18]，抽奖时，for循环匹配。
     */
    @Override
    public void armoryAlgorithm(String key, List<StrategyAwardEntity> strategyAwardEntities, BigDecimal rateRange) {
        log.info("抽奖算法 O(LogN) 装配 key:{}", key);
        // 范围边界起始位置
        int from = 1;
        // 范围边界结束位置
        int to = 0;
        // 定义缓存的map对象，
        Map<Integer, StrategyAwardRateRangeVO> table = new HashMap<>();
        // 基于奖品id进行排序
        strategyAwardEntities.sort(Comparator.comparing(StrategyAwardEntity::getAwardId));
        for(StrategyAwardEntity strategyAwardEntity : strategyAwardEntities){
            Integer awardId = strategyAwardEntity.getAwardId();
            BigDecimal awardRate = strategyAwardEntity.getAwardRate();
            to += rateRange.multiply(awardRate).intValue();
            StrategyAwardRateRangeVO strategyAwardRateRangeVO = new StrategyAwardRateRangeVO(from, to);
            table.put(awardId, strategyAwardRateRangeVO);
            from = to + 1;
        }
        strategyRepository.storeStrategyAwardSearchRateTable(key, to, table);
    }

    /**
     * 对每个奖品以及其概率范围进行map装配。根据奖品数进行判断才有循环、二分、多线程进行执行算法。
     */
    @Override
    public Integer dispatchAlgorithm(String key) {
        int rateRange = strategyRepository.getRateRange(key);
        // 查询缓存中的奖品概率返回集合
        Map<Integer, StrategyAwardRateRangeVO> table = strategyRepository.getCacheMap(key);
        // 小于等于8 for循环、小于等于16 二分查找、更多检索走多线程
        if (table.size() <= 6) {
            log.info("抽奖算法 OLog(n) 抽奖计算（循环） key:{}", key);
            return forSearch(secureRandom.nextInt(rateRange) + 1, table);
        } else if (table.size() <= 8) {
            log.info("抽奖算法 OLog(n) 抽奖计算（二分） key:{}", key);
            return binarySearch(secureRandom.nextInt(rateRange) + 1, table);
        } else {
            log.info("抽奖算法 OLog(n) 抽奖计算（多线程） key:{}", key);
            return threadSearch(secureRandom.nextInt(rateRange) + 1, table);
        }
    }

    private Integer forSearch(int rateKey, Map<Integer, StrategyAwardRateRangeVO> table) {
        Integer awardId = null;
        // 循环遍历map，根据rateRange是否在StrategyAwardRateRangeVO的startRange和endRange之间进行判断，如果存在，则返回对应的awardId。
        for (Map.Entry<Integer, StrategyAwardRateRangeVO> entry : table.entrySet()) {
            StrategyAwardRateRangeVO strategyAwardRateRangeVO = entry.getValue();
            if (rateKey >= strategyAwardRateRangeVO.getStartRange() && rateKey <= strategyAwardRateRangeVO.getEndRange()) {
                awardId = entry.getKey();
                break;
            }
        }
        return awardId;
    }
    private Integer binarySearch(int rateKey, Map<Integer, StrategyAwardRateRangeVO> table) {
        Integer awardId = null;
        // 对table 基于key进行排序
        ArrayList<Map.Entry<Integer, StrategyAwardRateRangeVO>> entries = new ArrayList<>(table.entrySet());
        entries.sort(Comparator.comparingInt(Map.Entry::getKey));
        // 二分查找，根据rateRange进行查找，如果存在，则返回对应的awardId。
        int left = 0;
        int right = table.size() - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (rateKey >= entries.get(mid).getValue().getStartRange() && rateKey <= entries.get(mid).getValue().getEndRange()) {
                awardId = entries.get(mid).getKey();
                break;
            } else if (rateKey < entries.get(mid).getValue().getStartRange()) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return awardId;
    }
    private Integer threadSearch(int rateKey, Map<Integer, StrategyAwardRateRangeVO> table) {
        List<CompletableFuture<Integer>> futures = new ArrayList<>();
        // 1. 创建并行任务
        for (Map.Entry<Integer, StrategyAwardRateRangeVO> entry : table.entrySet()) {
            StrategyAwardRateRangeVO vo = entry.getValue();

            CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
                // 检查当前范围是否包含rateKey
                if (rateKey >= vo.getStartRange() && rateKey <= vo.getEndRange()) {
                    return entry.getKey(); // 返回奖品ID
                }
                return null;
            }, threadPoolExecutor);

            futures.add(future);
        }

        // 2. 等待所有任务完成
        CompletableFuture<Void> allDone = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        try {
            allDone.join(); // 阻塞等待所有任务完成
        } catch (CompletionException e) {
            e.printStackTrace();
        }

        // 3. 遍历结果获取第一个匹配项
        for (CompletableFuture<Integer> future : futures) {
            Integer result = future.getNow(null);
            if (result != null) {
                return result;
            }
        }
        return null;
    }

}
